package filehandler

import (
	"fmt"
	"io/ioutil"
	"os"
	"sort"
	"strconv"
	"strings"
	"time"
)

type fileState struct {
	fileName string
	cursor   int64
}

func (p *FileScanner) readStatus() error {
	file, err := os.OpenFile(p.getStatusFileName(), os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
	if err != nil {
		p.runLog.Infoln("open file error", err.Error())
		return err
	}
	p.cursorMap.mp = make(map[string]int64)
	defer file.Close()
	bytes, err := ioutil.ReadAll(file)
	if err != nil {
		p.runLog.Infoln("read file error", err.Error())
		return err
	}
	if bytes == nil {
		return nil
	}
	if len(bytes) != 0 {
		content := string(bytes)
		lines := strings.Split(content, "\n")
		for k := range lines {
			if len(lines[k]) == 0 {
				continue
			}
			line := strings.Split(lines[k], "\t")
			cursor, err := strconv.ParseInt(line[1], 10, 64)
			if err != nil {
				p.runLog.Errorln("status file error:", lines[k])
				return err
			}
			p.cursorMap.mp[line[0]] = cursor
		}
	}
	return nil
}
func (p *FileScanner) writeStatus(force bool) {
	if p.statusLocked {
		if !force {
			return
		}
	}
	p.statusLocked = true
	defer func() {
		p.statusLocked = false
	}()
	file, err := os.OpenFile(p.getStatusFileName(), os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0666)
	if err != nil {
		p.runLog.Errorln("open file error", err.Error())
		return
	}
	defer file.Close()
	keySlice := []string{}
	p.cursorMap.Lock()
	for k := range p.cursorMap.mp {
		keySlice = append(keySlice, k)
	}
	sort.Sort(sort.StringSlice(keySlice))
	for _, v := range keySlice {
		line := fmt.Sprintf("%s\t%d\n", v, p.cursorMap.mp[v])
		file.WriteString(line)
	}

	p.cursorMap.Unlock()
}
func (p *FileScanner) getStatusFileName() string {
	return fmt.Sprintf("./status/status_%s", p.FileType)
}

func (p *fileHandler) printProgress(fileName string, startTime time.Time, lineSum, byteSum, newCursor, fileSize int64) {
	fileName = fileName[len(p.scanner.BaseDir):]
	passSec := int64(time.Now().Sub(startTime).Seconds())
	var bps, lps, ETASec int64
	if passSec != 0 {
		bps = byteSum / passSec
		//lps = lineSum / passSec
		ETASec = (fileSize - byteSum) / bps
	}
	var tpl int64 = 0
	if p.lineCount != 0 && p.costTime != 0 {
		tpl = p.costTime / p.lineCount
		lps = p.lineCount * 1000000 / p.costTime
	}
	p.qpsLog.Infofn("Cost:(%s) ETA:(%s) Byte:[%d KB/s | (%d / %d)MB %.2f%%]  Line:[%d Lines/s |%d μs/Line %d] [%s]",
		parseTime(passSec), parseTime(ETASec), bps/1e3, newCursor/1e6, fileSize/1e6, float64(newCursor*100)/float64(fileSize), lps, tpl, lineSum, fileName)
	p.costTime = 0
	p.lineCount = 0
}

func formatSize(bytes int64) string {
	if bytes < 1e3 {
		return fmt.Sprintf("%d B", bytes)
	}
	if bytes < 1e6 {
		return fmt.Sprintf("%d K", bytes/1e3)
	}
	return fmt.Sprintf("%d M", bytes/1e6)
}
func parseTime(s int64) string {
	if s <= 0 {
		return "00:00:00"
	}
	if s < 60 { // sec
		return fmt.Sprintf("00:00:%02d", s)
	}
	if s < 3600 { // min
		return fmt.Sprintf("00:%02d:%02d", s/60, s%60)
	}
	hour := s / 3600
	min := (s - hour*3600) / 60
	sec := (s - hour*3600 - min*60) % 60
	return fmt.Sprintf("%02d:%02d:%02d", hour, min, sec)
}
